import 'dart:io';

import 'package:dio/dio.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter_smart_heating/common/http.dart';
import 'package:flutter_smart_heating/ui/ui.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';

enum UiUploaderStatus {
  waiting,
  uploading,
  failed,
  done,
}

class UiUploaderData {
  String? path;
  String url;
  String? name;
  String? error;
  int? size;
  String type;
  double? progress;
  UiUploaderStatus status;
  UiUploaderData({
    this.path,
    this.name,
    this.size,
    this.progress,
    this.url = '',
    this.type = 'image',
    this.error,
    this.status = UiUploaderStatus.waiting,
  });
}

class UiUploader extends StatefulWidget {
  const UiUploader({
    super.key,
    this.max = 0,
    this.crossAxisCount = 4,
    this.crossAxisSpacing = 10,
    this.mainAxisSpacing = 10,
    this.autoUpload = true,
    this.onDeleted,
    this.onChanged,
  });

  ///最大上传文件数 0为不限
  final int max;

  /// 每列数量
  final int crossAxisCount;

  /// 横向间隔
  final double crossAxisSpacing;

  /// 垂直间隔
  final double mainAxisSpacing;

  /// 自动上传，选择完成后自动上传
  final bool autoUpload;

  /// 文件删除
  final Function(UiUploaderData file)? onDeleted;

  /// 文件列表改变
  final Function(List<String> files)? onChanged;

  @override
  State<UiUploader> createState() => _UiUploaderState();
}

class _UiUploaderState extends State<UiUploader> {
  List<UiUploaderData> files = [];
  CancelToken? cancelToken;

  /// 移除文件
  remove(int index) {
    var file = files[index];
    if (file.status == UiUploaderStatus.uploading) {
      cancelToken?.cancel('取消上传');
    }
    setState(() {
      files.removeAt(index);
    });
    widget.onDeleted?.call(file);
    callChanged();
  }

  /// 上传文件
  upload({int? index}) async {
    try {
      UiUploaderData file = index != null
          ? files[index]
          : files.firstWhere(
              (element) => element.status == UiUploaderStatus.waiting,
            );
      setState(() {
        file.status = UiUploaderStatus.uploading;
      });
      cancelToken = CancelToken();
      var res = await Http.instance.upload(
        '/api/user/upload/one',
        filePath: file.path.toString(),
        data: {"filetype": file.type},
        cancelToken: cancelToken,
        onSendProgress: (p0, p1) {
          setState(() {
            file.progress = p0 / p1;
          });
        },
      );
      if (res.code == 1) {
        file.status = UiUploaderStatus.done;
        file.url = res.data['filepath'];
      } else {
        file.error = res.msg;
        file.status = UiUploaderStatus.failed;
        file.progress = 0;
      }
      setState(() {
        file;
      });

      if (index == null) {
        upload();
      }
    } catch (e) {
      callChanged();
    }
  }

  /// 触发更新文件列表
  callChanged() {
    widget.onChanged?.call(
      files
          .where((element) => element.status == UiUploaderStatus.done)
          .map((e) => e.url)
          .toList(),
    );
  }

  @override
  Widget build(BuildContext context) {
    return StaggeredGrid.count(
      crossAxisCount: widget.crossAxisCount,
      crossAxisSpacing: widget.crossAxisSpacing,
      mainAxisSpacing: widget.mainAxisSpacing,
      children: [
        for (var i = 0; i < files.length; i++) fileView(files[i], i),
        if (widget.max == 0 || widget.max > files.length) pickView(),
      ],
    );
  }

  /// 文件预览
  Widget fileView(UiUploaderData item, int index) {
    File file = File(item.path.toString());
    return UiTap(
      onTap: () {
        if (item.type == 'video') {
          return Ui.toast('视频文件不支持预览');
        }
        Navigator.of(context).push(
          PageRouteBuilder(
            opaque: false,
            pageBuilder: (_, __, ___) => ImagePreview(
              url: file,
              allowToSave: false,
              title: '查看图片',
            ),
          ),
        );
      },
      child: Stack(
        children: [
          AspectRatio(
            aspectRatio: 1,
            child: Container(
              clipBehavior: Clip.hardEdge,
              decoration: BoxDecoration(
                color: Colors.grey[200],
                borderRadius: BorderRadius.circular(UiTheme.boxRadius),
              ),
              child: Hero(
                tag: file.toString(),
                child: Image.file(
                  file,
                  fit: BoxFit.cover,
                ),
              ),
            ),
          ),
          fileStatusView(item, index),
          Positioned(
            right: 0,
            top: 0,
            child: GestureDetector(
              behavior: HitTestBehavior.opaque,
              onTap: () {
                remove(index);
              },
              child: Container(
                padding: const EdgeInsets.all(2),
                decoration: const BoxDecoration(
                  color: Colors.black45,
                  borderRadius: BorderRadius.only(
                    topRight: Radius.circular(8),
                    bottomLeft: Radius.circular(5),
                  ),
                ),
                child: const Icon(
                  Icons.close,
                  color: Colors.white,
                  size: 16,
                ),
              ),
            ),
          )
        ],
      ),
    );
  }

  Widget fileStatusView(UiUploaderData file, index) {
    Widget child = Container();
    switch (file.status) {
      case UiUploaderStatus.uploading:
        child = Container(
          alignment: Alignment.center,
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              SizedBox(
                width: 20,
                height: 20,
                child: CircularProgressIndicator(
                  value: file.progress,
                  color: Colors.white,
                  strokeWidth: 3,
                ),
              ),
              const SizedBox(height: 5),
              Text(
                file.progress == null
                    ? '0%'
                    : '${(file.progress! * 100).toStringAsFixed(2)}%',
                style: const TextStyle(
                  color: Colors.white,
                  fontSize: 12,
                ),
              ),
            ],
          ),
        );
        break;
      case UiUploaderStatus.failed:
        child = UiTap(
          onTap: () {
            upload(index: index);
          },
          child: Container(
            alignment: Alignment.center,
            child: const Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Icon(
                  Icons.refresh,
                  size: 28,
                  color: Colors.white,
                ),
                UiTap(
                  child: Text(
                    '上传失败',
                    style: TextStyle(
                      color: Colors.white,
                      fontSize: 12,
                    ),
                  ),
                ),
              ],
            ),
          ),
        );
        break;
      case UiUploaderStatus.done:
        child = const Center(
          child: CircleAvatar(
            radius: 12,
            backgroundColor: Colors.green,
            child: Icon(
              Icons.check,
              size: 16,
              color: Colors.white,
            ),
          ),
        );
        break;
      default:
        child = Container();
    }

    return Positioned.fill(
        child: Container(
      decoration: BoxDecoration(
        color: Colors.black45,
        borderRadius: BorderRadius.circular(UiTheme.boxRadius),
      ),
      child: AnimatedSwitcher(
        duration: kThemeAnimationDuration,
        child: child,
      ),
    ));
  }

  /// 选择按钮
  Widget pickView() {
    return UiTap(
      onTap: () async {
        FilePickerResult? result = await FilePicker.platform.pickFiles(
          type: FileType.media,
          allowMultiple: widget.max == 0 || widget.max > 1,
        );

        if (result == null) {
          return;
        }
        for (var element in result.files) {
          if (widget.max == 0 || widget.max > files.length) {
            files.add(
              UiUploaderData(
                path: element.path,
                name: element.name,
                size: element.size,
                type: element.extension == 'mp4' ? 'video' : 'image',
              ),
            );
          }
        }
        setState(() {
          files;
        });

        ///自动上传
        if (widget.autoUpload) {
          upload();
        }
      },
      child: AspectRatio(
        aspectRatio: 1,
        child: Container(
          decoration: BoxDecoration(
            color: UiTheme(context).panelBackground,
            borderRadius: BorderRadius.circular(UiTheme.boxRadiusX),
            border: UiTheme.of(context).panelBorder,
          ),
          child: Center(
            child: Icon(
              Icons.add,
              size: 30,
              color: Colors.grey[600],
            ),
          ),
        ),
      ),
    );
  }
}
